1. Data Cleaning
Creating connection to the sqlite database and downloading fires dataset
# Connecting
conn <- dbConnect(SQLite(), 'raw_data/FPA_FOD_20170508.sqlite')
as.data.frame(dbListTables(conn))
# Making fires dataframe
fires <- tbl(conn, "Fires") %>% collect()
Selecting columns of interest
fires_small <- fires %>%
select(NWCG_REPORTING_AGENCY, SOURCE_REPORTING_UNIT_NAME, FIRE_NAME,
FIRE_YEAR, DISCOVERY_DATE, DISCOVERY_DOY, DISCOVERY_TIME, CONT_DATE,
CONT_DOY, CONT_TIME, STAT_CAUSE_CODE, STAT_CAUSE_DESCR, FIRE_SIZE,
FIRE_SIZE_CLASS, LATITUDE, LONGITUDE, OWNER_CODE, OWNER_DESCR, STATE,
COUNTY, FIPS_CODE, FIPS_NAME, Shape)
fires_small <- clean_names(fires_small)
Changing some columms to be factors
fires_small <- fires_small %>%
mutate(nwcg_reporting_agency = as.factor(nwcg_reporting_agency)) %>%
mutate(stat_cause_code = as.factor(stat_cause_code)) %>%
mutate(fire_size_class = as.factor(fire_size_class)) %>%
mutate(owner_descr = as.factor(owner_descr)) %>%
mutate(state = as.factor(state))
2. Creating some initial visualisations
Fires per year
fires_small %>%
group_by(fire_year) %>%
summarise(num_fires =n()) %>%
ggplot +
aes(x = fire_year, y = num_fires) +
geom_point() +
# geom_col(fill = "dark blue", col ="white") +
geom_smooth(method = "lm", se = FALSE, colour = "red")
`summarise()` ungrouping output (override with `.groups` argument)
Warning messages:
1: In `[<-.data.frame`(`*tmp*`, is_list, value = list(`23` = "<S3: blob>")) :
replacement element 1 has 1 row to replace 0 rows
2: In `[<-.data.frame`(`*tmp*`, is_list, value = list(`23` = "<S3: blob>")) :
replacement element 1 has 1 row to replace 0 rows
3: In `[<-.data.frame`(`*tmp*`, is_list, value = list(`23` = "<S3: blob>")) :
replacement element 1 has 1 row to replace 0 rows
4: In `[<-.data.frame`(`*tmp*`, is_list, value = list(`23` = "<S3: blob>")) :
replacement element 1 has 1 row to replace 0 rows
5: In `[<-.data.frame`(`*tmp*`, is_list, value = list(`23` = "<S3: blob>")) :
replacement element 1 has 1 row to replace 0 rows
6: In `[<-.data.frame`(`*tmp*`, is_list, value = list(`23` = "<S3: blob>")) :
replacement element 1 has 1 row to replace 0 rows
7: In `[<-.data.frame`(`*tmp*`, is_list, value = list(`23` = "<S3: blob>")) :
replacement element 1 has 1 row to replace 0 rows

It can be seen from the linear modelling smoother that there is a slight increase of wildfire over the recording period, but there is a lot of variation in the data between years. There is almost a repeating pattern occurring with 4 peaks visible. Having looked at the historic weather for that date range these peaks seems to coincide with recorded heatwaves in 2000, 2006 and 2011.
Fires per day
fires_small %>%
group_by(discovery_date) %>%
summarise(num_fires = n()) %>%
ggplot +
aes(x = discovery_date, y = num_fires) +
geom_line(col = "dark blue")
`summarise()` ungrouping output (override with `.groups` argument)

This shows a typical time series plot with a cyclic variation due to warmer weather in the summer time.
Fires per month
fires_small %>%
mutate(year_month = make_date(fire_year, discovery_moy)) %>%
group_by(year_month) %>%
summarise(num_fires = n()) %>%
ggplot +
aes(x = year_month, y = num_fires) +
geom_line(col = "dark blue")
`summarise()` ungrouping output (override with `.groups` argument)

Peaks are still shown to be occurring in the summer. The 2006 heatwave is especially visable.
Fires by day of year
fires_small %>%
group_by(discovery_doy) %>%
summarise(num_fires = n()) %>%
ggplot(aes(x = discovery_doy, y = num_fires)) +
geom_line(col = "dark blue")
`summarise()` ungrouping output (override with `.groups` argument)

The are peaks around day 60-110 and a big peak around 180.
Checking the data to see where the peak occurs
fires_small %>%
group_by(discovery_doy) %>%
summarise(num_fires = n()) %>%
arrange(desc(num_fires))
`summarise()` ungrouping output (override with `.groups` argument)
The 2 highest days of the year are on 185 and 186, which happens to be Independence Day (4th July) on a normal year and a leap year retrospectively. So I imagine most of the extra fires (literally over double the normal amount) are caused by fireworks.
Fires by month of year
fires_small %>%
mutate(discovery_moy = (month(ymd(discovery_date), label = TRUE))) %>%
group_by(discovery_moy) %>%
summarise(num_fires = n()) %>%
ggplot(aes(x = discovery_moy, y = num_fires)) +
geom_col(fill = "dark blue", col = "white")
`summarise()` ungrouping output (override with `.groups` argument)

There are 2 definite peaks during the year. March and April are probably due to the US “Spring Break”, where schools and Universities are stopped and so families are likely to be on vacation during that period possibly visiting National Parks. July and August is also Summer Break for school with both families visiting Parks and hot weather likely causes of fire outbreaks.
Fires by cause
options(scipen = 999)
fires_small %>%
group_by(stat_cause_descr) %>%
summarise(num_fires = n()) %>%
ggplot +
aes(reorder(x = stat_cause_descr, num_fires), y = num_fires) +
geom_col(fill = "dark blue") +
coord_flip()
`summarise()` ungrouping output (override with `.groups` argument)

Fire avg size by cause
fires_small %>%
group_by(stat_cause_descr) %>%
summarise(avg_size = mean(fire_size)) %>%
ggplot +
aes(reorder(x = stat_cause_descr, avg_size), y = avg_size) +
geom_col(fill = "dark blue") +
coord_flip()
`summarise()` ungrouping output (override with `.groups` argument)

Avg burn time by cause
fires_small %>%
summarise(num_na = sum(is.na(cont_date)))
Literally half the data is missing for burn time, making it very difficult to do any meaningful analysis
Fires by size
fires_small %>%
group_by(fire_size_class) %>%
summarise(num_fires = n()) %>%
ggplot +
aes(x = fire_size_class, y = num_fires, fill = fire_size_class) +
geom_col() +
scale_fill_manual(values = c("red", "orange", "yellow", "green", "blue",
"purple", "black"),
name = "Fire Size Classification",
breaks = c("A", "B", "C", "D", "E", "F", "G"),
labels = c("A: < 1/4 acre", "B: 1/4 to 10 acres", "C: 10 to 100 acres",
"D: 100 to 300 acres", "E: 300 to 1000 acres",
"F: 1000 to 5000 acres", "G: More than 5000 acres"))
`summarise()` ungrouping output (override with `.groups` argument)

3. Geo Spatial Visualisations
The dataset has a cause of fire column so I shall now create some causation plots.
Getting list of fire causes
fires_states %>%
distinct(stat_cause_descr) %>%
arrange(-desc(stat_cause_descr))
Wildfires caused by Arson
cause("Arson")
`summarise()` ungrouping output (override with `.groups` argument)

Arson does seem more prevalent in the SE states of Mississippi, Georgia, Alabama and also the western state of California.
Wildfires caused by Campfire
cause("Campfire")
`summarise()` ungrouping output (override with `.groups` argument)

Campfires are the most prevalent in the Western states of Oregon, California and Arizona.
Wildfires caused by Children
cause("Children")
`summarise()` ungrouping output (override with `.groups` argument)

Fires by children are spread about the country, but the most prevalent states are California in the West, Alabama and South Carolina and New Jersey in the east.
Wildfires caused by Debris Burning
cause("Debris Burning")
`summarise()` ungrouping output (override with `.groups` argument)

Fires by burning debris are mostly in the southern warmer states of Texas, Georgia and North Carolina.
Wildfires caused by Equiment Use
cause("Equipment Use")
`summarise()` ungrouping output (override with `.groups` argument)

Most of the fires caused by equipment seem to be in California
Wildfires caused by Fireworks
cause("Fireworks")
`summarise()` ungrouping output (override with `.groups` argument)

Most of the fires caused by fireworks seem to be in the north of the country. Primarily South Dakota, Montana and Washington state.
Wildfires caused by Lightning
cause("Lightning")
`summarise()` ungrouping output (override with `.groups` argument)

Apart from a hotspot of lightning strikes in Florida, the vast majority of fires caused by lightning are in the West of the country. With the 3 most affected states being California, Oregon and Arizona.
Wildfires caused by Miscellious
cause("Miscellaneous")
`summarise()` ungrouping output (override with `.groups` argument)

There seems to be quite a few miscellaneous classifications in California, Texas and New York.
Wildfires caused by Missing/Undefined
cause("Missing/Undefined")
`summarise()` ungrouping output (override with `.groups` argument)

The states with the most missing or undefined data is North and South Carolina, Oklahoma and California.
Wildfires caused by Powerline
cause("Powerline")
`summarise()` ungrouping output (override with `.groups` argument)

Texas has the largest amount of wildfires caused by powerlines. This is likely due to the warm climate and the large proportion of the state that is dry grasslands used for agriculture.
Wildfires caused by Railroad
cause("Railroad")
`summarise()` ungrouping output (override with `.groups` argument)

By far Florida has the most wildfires caused by railroads.
Wildfires caused by Smoking
cause("Smoking")
`summarise()` ungrouping output (override with `.groups` argument)

Fires caused by smoking seem to be spread around the country, but mainly on the east and west coasts.
Wildfires caused by Structure
cause("Structure")
`summarise()` ungrouping output (override with `.groups` argument)

South Dakota has the largest proportion of fires caused by structures.
Unsurprisingly the southern states seem to have more occurences of wildifre in general, no doubt due to the warmer climate at their latitudes. Also the 1st and 3rd states with the highest number of fires are also the 2 largest States by size. However the 2nd highest State is Georgia, which although it is in the South of the country is only an average sized State. Therefore to get a better picture of what is going on I’m going to look at the proportion of fires occuring by square mile by normalising the State size.
The dataset package also has the area in square miles of each state included in the state.area vector.
state.area
[1] 51609 589757 113909 53104 158693 104247 5009 2057 58560 58876 6450
[12] 83557 56400 36291 56290 82264 40395 48523 33215 10577 8257 58216
[23] 84068 47716 69686 147138 77227 110540 9304 7836 121666 49576 52586
[34] 70665 41222 69919 96981 45333 1214 31055 77047 42244 267339 84916
[45] 9609 40815 68192 24181 56154 97914
length(state.area)
[1] 50
Annoyingly it also only has 50 states not 52 so I will need to add in DC and PR back in.
(Area figures obtained from Wikipedia)
DC = 68 miles^2 PR = 3515 miles^2
# To make my life easier I'm going to remove the state.abb and .name files and make the tibble again, adding in the land area figures at the same time to make sure they are in the correct order.
rm(state.abb)
rm(state.name)
state.abb <- append(state.abb, c("DC", "PR"))
state.name <- append(state.name, c("District of Columbia", "Puerto Rico"))
state.area <- append(state.area, c("68", "3515"))
state_list <- tibble(state = state.abb, region = tolower(state.name), area = as.numeric(state.area))
# Re-joing tibbles
fires_states <- fires_small %>%
left_join(state_list, by = "state")
Normalising States area sizes
fires_states %>%
select(region, area) %>%
group_by(region, area) %>%
summarise(num_fires = n()) %>%
mutate(fires_sqmile = num_fires / area) %>%
arrange(desc(fires_sqmile))
`summarise()` regrouping output by 'region' (override with `.groups` argument)
This table shows Puerto Rico has the highest proportion of fires compared to its size, followed by New Jersey in the NE of the country and finally by the States in the SE of the country.
fires_states %>%
select(region, area) %>%
group_by(region, area) %>%
summarise(num_fires = n()) %>%
mutate(fires_sqmile = num_fires / area) %>%
right_join(state_map, by = "region") %>%
ggplot +
(aes(x = long, y = lat, group = group, fill = fires_sqmile)) +
geom_polygon() +
geom_path(color = "white") +
scale_fill_distiller(name = "Fire per Sq Mile", palette = "PuBuGn") +
#scale_fill_continuous(low = "darkblue",
# high = "darkred",
# name = "Fire per Sq mile") +
theme_map() +
coord_map("mollweide") +
ggtitle(paste0("Total US Wildfires per Square Mile from 1992-2015")) +
theme(plot.title = element_text(hjust = 0.5))
`summarise()` regrouping output by 'region' (override with `.groups` argument)

Puerto Rico is not shown on this map, but visually we can see the data for the other 51 entries, and the south eastern states still have the highest proportion of wildfires. Interestingly New Jersey also shows has a hotspot in the NE of the country.
Do causes change over time?
Splitting causes into 2 group for legibility.
The first group is for directly man created fires.
fires_states %>%
select(stat_cause_descr, fire_year) %>%
group_by(fire_year, stat_cause_descr) %>%
filter(stat_cause_descr == "Arson" | stat_cause_descr == "Campfire" |
stat_cause_descr == "Children" | stat_cause_descr == "Equipment Use" |
stat_cause_descr == "Fireworks" | stat_cause_descr == "Smoking") %>%
summarise(num_fires = n()) %>%
ggplot +
aes(x = fire_year, y = num_fires, colour = stat_cause_descr) +
geom_line()
`summarise()` regrouping output by 'fire_year' (override with `.groups` argument)
Warning message:
In `[<-.data.frame`(`*tmp*`, is_list, value = list(`23` = "<S3: blob>")) :
replacement element 1 has 1 row to replace 0 rows

The 2 large peaks in Arson are obvious in 1999 and 2006. There was a large heatwave in 2006, but I’m not sure why this would result in an increase in arson. Unless this was jsut due to the dry ground creating extra fuel to aid the spread of fires that would have normally not resulted in a large scale fire. This may also be the same reason that there is also another peak in 2006 for Equipment Use. Arson however does look to be decreasing since 2006.
And this one for natural occuring fires.
fires_states %>%
select(stat_cause_descr, fire_year) %>%
group_by(fire_year, stat_cause_descr) %>%
filter(stat_cause_descr == "Debris Burning" | stat_cause_descr == "Lightning" |
stat_cause_descr == "Miscellaneous" | stat_cause_descr ==
"Missing/Undefined" | stat_cause_descr == "Powerline" |
stat_cause_descr == "Railroad" | stat_cause_descr == "Structure") %>%
summarise(num_fires = n()) %>%
ggplot +
aes(x = fire_year, y = num_fires, colour = stat_cause_descr) +
geom_line()
`summarise()` regrouping output by 'fire_year' (override with `.groups` argument)

Similar peaks can be seen in Debris, Miscellaneous and lightning in the heatwave of 2006 that left the ground very dry. There are peaks from 1997 to 2003 in debris, miscellaneous and lightening, but also a trough in missing/undefined, so this is likely to be due to more accurate classification of fires and not using the missing/undefined category as much.
Difference in causes between states
state_map_southern <- state_map %>%
filter(region == "florida" | region == "georgia" | region == "alabama" |
region == "mississippi" | region == "south carolina" |
region == "north carolina" | region == "tennessee" |
region == "arkansas" | region == "louisiana")
fires_states %>%
filter(fire_year == "1992" | fire_year == "1993" | fire_year == "1994" |
fire_year == "1995") %>%
filter(region == "florida" | region == "georgia" | region == "alabama" |
region == "mississippi" | region == "south carolina" |
region == "north carolina" | region == "tennessee" |
region == "arkansas" | region == "louisiana") %>%
select(region, stat_cause_descr) %>%
group_by(region, stat_cause_descr) %>%
summarise(num_fire = n()) %>%
top_n(1) %>%
right_join(state_map_southern, by = "region") %>%
ggplot +
(aes(x = long, y = lat, group = group, fill = stat_cause_descr)) +
geom_polygon() +
geom_path(color = "white") +
theme_map() +
scale_fill_brewer(name = "Cause of Fires", palette = "PuBuGn") +
ggtitle("Total US Wildfires main cause from 1992-1995") +
theme(plot.title = element_text(hjust = 0.5))
`summarise()` regrouping output by 'region' (override with `.groups` argument)
Selecting by num_fire

fires_states %>%
filter(fire_year == "1996" | fire_year == "1997" | fire_year == "1998" |
fire_year == "1999") %>%
filter(region == "florida" | region == "georgia" | region == "alabama" |
region == "mississippi" | region == "south carolina" |
region == "north carolina" | region == "tennessee" |
region == "arkansas" | region == "louisiana") %>%
select(region, stat_cause_descr) %>%
group_by(region, stat_cause_descr) %>%
summarise(num_fire = n()) %>%
top_n(1) %>%
right_join(state_map_southern, by = "region") %>%
ggplot +
(aes(x = long, y = lat, group = group, fill = stat_cause_descr)) +
geom_polygon() +
geom_path(color = "white") +
theme_map() +
scale_fill_brewer(name = "Cause of Fires", palette = "PuBuGn") +
ggtitle("Total US Wildfires main cause from 1996-1999") +
theme(plot.title = element_text(hjust = 0.5))
`summarise()` regrouping output by 'region' (override with `.groups` argument)
Selecting by num_fire

fires_states %>%
filter(fire_year == "2000" | fire_year == "2001" | fire_year == "2002" |
fire_year == "2003") %>%
filter(region == "florida" | region == "georgia" | region == "alabama" |
region == "mississippi" | region == "south carolina" |
region == "north carolina" | region == "tennessee" |
region == "arkansas" | region == "louisiana") %>%
select(region, stat_cause_descr) %>%
group_by(region, stat_cause_descr) %>%
summarise(num_fire = n()) %>%
top_n(1) %>%
right_join(state_map_southern, by = "region") %>%
ggplot +
(aes(x = long, y = lat, group = group, fill = stat_cause_descr)) +
geom_polygon() +
geom_path(color = "white") +
theme_map() +
scale_fill_brewer(name = "Cause of Fires", palette = "PuBuGn") +
ggtitle("Total US Wildfires main cause from 2000-2003") +
theme(plot.title = element_text(hjust = 0.5))
`summarise()` regrouping output by 'region' (override with `.groups` argument)
Selecting by num_fire

fires_states %>%
filter(fire_year == "2004" | fire_year == "2005" | fire_year == "2006" |
fire_year == "2007") %>%
filter(region == "florida" | region == "georgia" | region == "alabama" |
region == "mississippi" | region == "south carolina" |
region == "north carolina" | region == "tennessee" |
region == "arkansas" | region == "louisiana") %>%
select(region, stat_cause_descr) %>%
group_by(region, stat_cause_descr) %>%
summarise(num_fire = n()) %>%
top_n(1) %>%
right_join(state_map_southern, by = "region") %>%
ggplot +
(aes(x = long, y = lat, group = group, fill = stat_cause_descr)) +
geom_polygon() +
geom_path(color = "white") +
theme_map() +
scale_fill_brewer(name = "Cause of Fires", palette = "PuBuGn") +
ggtitle("Total US Wildfires main cause from 2004-2007") +
theme(plot.title = element_text(hjust = 0.5))
`summarise()` regrouping output by 'region' (override with `.groups` argument)
Selecting by num_fire

fires_states %>%
filter(fire_year == "2008" | fire_year == "2009" | fire_year == "2010" |
fire_year == "2011") %>%
filter(region == "florida" | region == "georgia" | region == "alabama" |
region == "mississippi" | region == "south carolina" |
region == "north carolina" | region == "tennessee" |
region == "arkansas" | region == "louisiana") %>%
select(region, stat_cause_descr) %>%
group_by(region, stat_cause_descr) %>%
summarise(num_fire = n()) %>%
top_n(1) %>%
right_join(state_map_southern, by = "region") %>%
ggplot +
(aes(x = long, y = lat, group = group, fill = stat_cause_descr)) +
geom_polygon() +
geom_path(color = "white") +
theme_map() +
scale_fill_brewer(name = "Cause of Fires", palette = "PuBuGn") +
ggtitle("Total US Wildfires main cause from 2008-2011") +
theme(plot.title = element_text(hjust = 0.5))
`summarise()` regrouping output by 'region' (override with `.groups` argument)
Selecting by num_fire

fires_states %>%
filter(fire_year == "2012" | fire_year == "2013" | fire_year == "2014" |
fire_year == "2015") %>%
filter(region == "florida" | region == "georgia" | region == "alabama" |
region == "mississippi" | region == "south carolina" |
region == "north carolina" | region == "tennessee" |
region == "arkansas" | region == "louisiana") %>%
select(region, stat_cause_descr) %>%
group_by(region, stat_cause_descr) %>%
summarise(num_fire = n()) %>%
top_n(1) %>%
right_join(state_map_southern, by = "region") %>%
ggplot +
(aes(x = long, y = lat, group = group, fill = stat_cause_descr)) +
geom_polygon() +
geom_path(color = "white") +
theme_map() +
scale_fill_brewer(name = "Cause of Fires", palette = "PuBuGn") +
ggtitle("Total US Wildfires main cause from 2012-2015") +
theme(plot.title = element_text(hjust = 0.5))
`summarise()` regrouping output by 'region' (override with `.groups` argument)
Selecting by num_fire

Looking at these trends some interesting insights can be seen. For the combined years data Florida stands out as having railroad as its main cause of wildfire, but from the above plots it can be seen that these railroad fires are only the main cause up to the 4 yearly period ending in 2003 and then the main cause changes to lightning until the end of the collection period in 2015. Similarly arson seem reasonably popular in the southern states until 2007, when it no longer appear as the most common cause of wildfire. This downward trend was also noted earlier in the overall causation plots for all states
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KFJTUUxpdGUpCmxpYnJhcnkoZGJwbHlyKQpsaWJyYXJ5KGphbml0b3IpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KGRhdGFzZXRzKQpsaWJyYXJ5KGdndGhlbWVzKQpsaWJyYXJ5KGdnYW5pbWF0ZSkKYGBgCgoKIyAxLiAgRGF0YSBDbGVhbmluZwoKCiMjIyMgIENyZWF0aW5nIGNvbm5lY3Rpb24gdG8gdGhlIHNxbGl0ZSBkYXRhYmFzZSBhbmQgZG93bmxvYWRpbmcgZmlyZXMgZGF0YXNldAoKYGBge3J9CiMgQ29ubmVjdGluZwoKY29ubiA8LSBkYkNvbm5lY3QoU1FMaXRlKCksICJyYXdfZGF0YS9GUEFfRk9EXzIwMTcwNTA4LnNxbGl0ZSIpCmBgYAoKYGBge3J9CiMgUHVsbGluZyBhbGwgdGhlIG5hbWVzIG9mIHRoZSB0YWJsZXMgaW4gdGhlIGRhdGFiYXNlIGZpbGUKCmFzLmRhdGEuZnJhbWUoZGJMaXN0VGFibGVzKGNvbm4pKQpgYGAKCmBgYHtyfQojIE1ha2luZyBmaXJlcyBkYXRhZnJhbWUKCmZpcmVzIDwtIHRibChjb25uLCAiRmlyZXMiKSAlPiUgY29sbGVjdCgpCmBgYAoKCiMjIyMgU2VlaW5nIHdoYXQgb3RoZXIgdXNlZnVsIGluZm9ybWF0aW9uIGlzIGluIHRoZSBkYXRhYmFzZS4gIFRoZSBtYWpvcml0eSBhcmUgcGFydCBvZiB0aGUgZGF0YWJhc2Ugc3RydWN0dXJlIGFuZCBhcmUgbm90IHJlYWRhYmxlIGluIFIuCgpgYGB7cn0KIyBFUFNHIHdvcmxkd2lkZSBnZW9kZXRpYyBwYXJhbWV0ZXIgZGF0YXNldCBzeXN0ZW0Kc3BhdGlhbF9yZWYgPC0gdGJsKGNvbm4sICJzcGF0aWFsX3JlZl9zeXNfYWxsIikgJT4lIGNvbGxlY3QoKQoKIyBOYXRpb25hbCBXaWxkZmlyZSBDb29yZGluYXRpbmcgR3JvdXAgdW5pdCBhYmJyZXZpYXRpb25zIApOV0dHIDwtIHRibChjb25uLCAiTldDR19Vbml0SURBY3RpdmVfMjAxNzAxMDkiKSAlPiUgY29sbGVjdCgpCmBgYAoKCmBgYHtyfQojIERpc2Nvbm5lY3QKCmRiRGlzY29ubmVjdChjb25uKQpgYGAKCgojIyMgU2VsZWN0aW5nIGNvbHVtbnMgb2YgaW50ZXJlc3QKCmBgYHtyfQpmaXJlc19zbWFsbCA8LSBmaXJlcyAlPiUKICBzZWxlY3QoTldDR19SRVBPUlRJTkdfQUdFTkNZLCBTT1VSQ0VfUkVQT1JUSU5HX1VOSVRfTkFNRSwgRklSRV9OQU1FLAogICAgICAgICBGSVJFX1lFQVIsIERJU0NPVkVSWV9EQVRFLCBESVNDT1ZFUllfRE9ZLCBESVNDT1ZFUllfVElNRSwgQ09OVF9EQVRFLAogICAgICAgICBDT05UX0RPWSwgQ09OVF9USU1FLCBTVEFUX0NBVVNFX0NPREUsIFNUQVRfQ0FVU0VfREVTQ1IsIEZJUkVfU0laRSwgCiAgICAgICAgIEZJUkVfU0laRV9DTEFTUywgTEFUSVRVREUsIExPTkdJVFVERSwgT1dORVJfQ09ERSwgT1dORVJfREVTQ1IsIFNUQVRFLCAKICAgICAgICAgQ09VTlRZLCBGSVBTX0NPREUsIEZJUFNfTkFNRSwgU2hhcGUpCgpmaXJlc19zbWFsbCA8LSBjbGVhbl9uYW1lcyhmaXJlc19zbWFsbCkKYGBgCgoKIyMjIENoYW5naW5nIHNvbWUgY29sdW1tcyB0byBiZSBmYWN0b3JzCgpgYGB7cn0KZmlyZXNfc21hbGwgPC0gZmlyZXNfc21hbGwgJT4lCiAgbXV0YXRlKG53Y2dfcmVwb3J0aW5nX2FnZW5jeSA9IGFzLmZhY3Rvcihud2NnX3JlcG9ydGluZ19hZ2VuY3kpKSAlPiUKICBtdXRhdGUoc3RhdF9jYXVzZV9jb2RlID0gYXMuZmFjdG9yKHN0YXRfY2F1c2VfY29kZSkpICU+JQogIG11dGF0ZShmaXJlX3NpemVfY2xhc3MgPSBhcy5mYWN0b3IoZmlyZV9zaXplX2NsYXNzKSkgJT4lCiAgbXV0YXRlKG93bmVyX2Rlc2NyID0gYXMuZmFjdG9yKG93bmVyX2Rlc2NyKSkgJT4lCiAgbXV0YXRlKHN0YXRlID0gYXMuZmFjdG9yKHN0YXRlKSkgCmBgYAoKCiMjIyBEYXRlIGlzIGluIEp1bGlhbiBmb3JtYXQsIHNvIG92ZXJ3cml0aW5nIHdpdGggR3JlZ29yaWFuIGZvcm1hdCB1c2luZyB5ZWFyIGFuZCBkYXkgb2YgeWVhciBjb2x1bW5zLiAgQWxzbyBhZGRpbmcgaW4gYSAnbW9udGggb2YgeWVhciBjb2x1bW4nIGZvciBmdXR1cmUgdXNlLgoKYGBge3J9CmZpcmVzX3NtYWxsIDwtIGZpcmVzX3NtYWxsICU+JQogIG11dGF0ZShkYXRlX29yaWdpbiA9IGFzLkRhdGUocGFzdGUwKGZpcmVfeWVhciwgIi0wMS0wMSIpKSkgJT4lCiAgbXV0YXRlKGRpc2NvdmVyeV9kYXRlID0gYXMuRGF0ZShkaXNjb3ZlcnlfZG95LCBvcmlnaW4gPSBkYXRlX29yaWdpbikpICU+JQogIG11dGF0ZShkaXNjb3ZlcnlfbW95ID0gbW9udGgoZGlzY292ZXJ5X2RhdGUpKSAlPiUKICBzZWxlY3QoLWRhdGVfb3JpZ2luKQpgYGAKCgoKIyAyLiBDcmVhdGluZyBzb21lIGluaXRpYWwgdmlzdWFsaXNhdGlvbnMKCgojIyMgRmlyZXMgcGVyIHllYXIKCmBgYHtyfQpmaXJlc19zbWFsbCAlPiUKICBncm91cF9ieShmaXJlX3llYXIpICU+JQogIHN1bW1hcmlzZShudW1fZmlyZXMgPW4oKSkgJT4lCiAgZ2dwbG90ICsKICBhZXMoeCA9IGZpcmVfeWVhciwgeSA9IG51bV9maXJlcykgKwogIGdlb21fcG9pbnQoKSArCiAgIyBnZW9tX2NvbChmaWxsID0gImRhcmsgYmx1ZSIsIGNvbCA9IndoaXRlIikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG91ciA9ICJyZWQiKQpgYGAKKipJdCBjYW4gYmUgc2VlbiBmcm9tIHRoZSBsaW5lYXIgbW9kZWxsaW5nIHNtb290aGVyIHRoYXQgdGhlcmUgaXMgYSBzbGlnaHQgaW5jcmVhc2Ugb2Ygd2lsZGZpcmUgb3ZlciB0aGUgcmVjb3JkaW5nIHBlcmlvZCwgYnV0IHRoZXJlIGlzIGEgbG90IG9mIHZhcmlhdGlvbiBpbiB0aGUgZGF0YSBiZXR3ZWVuIHllYXJzLiAgVGhlcmUgaXMgYWxtb3N0IGEgcmVwZWF0aW5nIHBhdHRlcm4gb2NjdXJyaW5nIHdpdGggNCBwZWFrcyB2aXNpYmxlLiAgSGF2aW5nIGxvb2tlZCBhdCB0aGUgaGlzdG9yaWMgd2VhdGhlciBmb3IgdGhhdCBkYXRlIHJhbmdlIHRoZXNlIHBlYWtzIHNlZW1zIHRvIGNvaW5jaWRlIHdpdGggcmVjb3JkZWQgaGVhdHdhdmVzIGluIDIwMDAsIDIwMDYgYW5kIDIwMTEuKioKCgojIyMgRmlyZXMgcGVyIGRheQoKYGBge3J9CmZpcmVzX3NtYWxsICU+JQogIGdyb3VwX2J5KGRpc2NvdmVyeV9kYXRlKSAlPiUKICBzdW1tYXJpc2UobnVtX2ZpcmVzID0gbigpKSAlPiUKICBnZ3Bsb3QgKwogIGFlcyh4ID0gZGlzY292ZXJ5X2RhdGUsIHkgPSBudW1fZmlyZXMpICsKICBnZW9tX2xpbmUoY29sID0gImRhcmsgYmx1ZSIpCgpgYGAKCioqVGhpcyBzaG93cyBhIHR5cGljYWwgdGltZSBzZXJpZXMgcGxvdCB3aXRoIGEgY3ljbGljIHZhcmlhdGlvbiBkdWUgdG8gd2FybWVyIHdlYXRoZXIgaW4gdGhlIHN1bW1lciB0aW1lLioqCgoKIyMjIEZpcmVzIHBlciBtb250aAoKYGBge3J9CmZpcmVzX3NtYWxsICU+JQogIG11dGF0ZSh5ZWFyX21vbnRoID0gbWFrZV9kYXRlKGZpcmVfeWVhciwgZGlzY292ZXJ5X21veSkpICU+JQogIGdyb3VwX2J5KHllYXJfbW9udGgpICU+JQogIHN1bW1hcmlzZShudW1fZmlyZXMgPSBuKCkpICU+JQogIGdncGxvdCArCiAgYWVzKHggPSB5ZWFyX21vbnRoLCB5ID0gbnVtX2ZpcmVzKSArCiAgZ2VvbV9saW5lKGNvbCA9ICJkYXJrIGJsdWUiKQpgYGAKCioqUGVha3MgYXJlIHN0aWxsIHNob3duIHRvIGJlIG9jY3VycmluZyBpbiB0aGUgc3VtbWVyLiBUaGUgMjAwNiBoZWF0d2F2ZSBpcyBlc3BlY2lhbGx5IHZpc2FibGUuKioKCgojIyMgRmlyZXMgYnkgZGF5IG9mIHllYXIKCgpgYGB7cn0KZmlyZXNfc21hbGwgJT4lCiAgZ3JvdXBfYnkoZGlzY292ZXJ5X2RveSkgJT4lCiAgc3VtbWFyaXNlKG51bV9maXJlcyA9IG4oKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gZGlzY292ZXJ5X2RveSwgeSA9IG51bV9maXJlcykpICsKICBnZW9tX2xpbmUoY29sID0gImRhcmsgYmx1ZSIpCmBgYAoKKipUaGUgYXJlIHBlYWtzIGFyb3VuZCBkYXkgNjAtMTEwIGFuZCBhIGJpZyBwZWFrIGFyb3VuZCAxODAuKioKCiMjIyMgQ2hlY2tpbmcgdGhlIGRhdGEgdG8gc2VlIHdoZXJlIHRoZSBwZWFrIG9jY3VycwoKYGBge3J9CmZpcmVzX3NtYWxsICU+JQogIGdyb3VwX2J5KGRpc2NvdmVyeV9kb3kpICU+JQogIHN1bW1hcmlzZShudW1fZmlyZXMgPSBuKCkpICU+JQogIGFycmFuZ2UoZGVzYyhudW1fZmlyZXMpKQpgYGAKKipUaGUgMiBoaWdoZXN0IGRheXMgb2YgdGhlIHllYXIgYXJlIG9uIDE4NSBhbmQgMTg2LCB3aGljaCBoYXBwZW5zIHRvIGJlIEluZGVwZW5kZW5jZSBEYXkgKDR0aCBKdWx5KSBvbiBhIG5vcm1hbCB5ZWFyIGFuZCBhIGxlYXAgeWVhciByZXRyb3NwZWN0aXZlbHkuICBTbyBJIGltYWdpbmUgbW9zdCBvZiB0aGUgZXh0cmEgZmlyZXMgKGxpdGVyYWxseSBvdmVyIGRvdWJsZSB0aGUgbm9ybWFsIGFtb3VudCkgYXJlIGNhdXNlZCBieSBmaXJld29ya3MuKioKCgoKIyMjIEZpcmVzIGJ5IG1vbnRoIG9mIHllYXIKCmBgYHtyfQpmaXJlc19zbWFsbCAlPiUKICBtdXRhdGUoZGlzY292ZXJ5X21veSA9IChtb250aCh5bWQoZGlzY292ZXJ5X2RhdGUpLCBsYWJlbCA9IFRSVUUpKSkgJT4lCiAgZ3JvdXBfYnkoZGlzY292ZXJ5X21veSkgJT4lCiAgc3VtbWFyaXNlKG51bV9maXJlcyA9IG4oKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gZGlzY292ZXJ5X21veSwgeSA9IG51bV9maXJlcykpICsKICBnZW9tX2NvbChmaWxsID0gImRhcmsgYmx1ZSIsIGNvbCA9ICJ3aGl0ZSIpCmBgYAoKKipUaGVyZSBhcmUgMiBkZWZpbml0ZSBwZWFrcyBkdXJpbmcgdGhlIHllYXIuICBNYXJjaCBhbmQgQXByaWwgYXJlIHByb2JhYmx5IGR1ZSB0byB0aGUgVVMgIlNwcmluZyBCcmVhayIsIHdoZXJlIHNjaG9vbHMgYW5kIFVuaXZlcnNpdGllcyBhcmUgc3RvcHBlZCBhbmQgc28gZmFtaWxpZXMgYXJlIGxpa2VseSB0byBiZSBvbiB2YWNhdGlvbiBkdXJpbmcgdGhhdCBwZXJpb2QgcG9zc2libHkgdmlzaXRpbmcgTmF0aW9uYWwgUGFya3MuICBKdWx5IGFuZCBBdWd1c3QgaXMgYWxzbyBTdW1tZXIgQnJlYWsgZm9yIHNjaG9vbCB3aXRoIGJvdGggZmFtaWxpZXMgdmlzaXRpbmcgUGFya3MgYW5kIGhvdCB3ZWF0aGVyIGxpa2VseSBjYXVzZXMgb2YgZmlyZSBvdXRicmVha3MuKioKCgoKCiMjIyBGaXJlcyBieSBjYXVzZQoKYGBge3J9Cm9wdGlvbnMoc2NpcGVuID0gOTk5KQoKZmlyZXNfc21hbGwgJT4lCiAgZ3JvdXBfYnkoc3RhdF9jYXVzZV9kZXNjcikgJT4lCiAgc3VtbWFyaXNlKG51bV9maXJlcyA9IG4oKSkgJT4lCiAgZ2dwbG90ICsKICBhZXMocmVvcmRlcih4ID0gc3RhdF9jYXVzZV9kZXNjciwgbnVtX2ZpcmVzKSwgeSA9IG51bV9maXJlcykgKwogIGdlb21fY29sKGZpbGwgPSAiZGFyayBibHVlIikgKyAKICBjb29yZF9mbGlwKCkgCmBgYAoKCiMjIyBGaXJlIGF2ZyBzaXplIGJ5IGNhdXNlCgpgYGB7cn0KZmlyZXNfc21hbGwgJT4lCiAgZ3JvdXBfYnkoc3RhdF9jYXVzZV9kZXNjcikgJT4lCiAgc3VtbWFyaXNlKGF2Z19zaXplID0gbWVhbihmaXJlX3NpemUpKSAlPiUKICBnZ3Bsb3QgKwogIGFlcyhyZW9yZGVyKHggPSBzdGF0X2NhdXNlX2Rlc2NyLCBhdmdfc2l6ZSksIHkgPSBhdmdfc2l6ZSkgKwogIGdlb21fY29sKGZpbGwgPSAiZGFyayBibHVlIikgKyAKICBjb29yZF9mbGlwKCkKYGBgCgoKIyMjIEF2ZyBidXJuIHRpbWUgYnkgY2F1c2UKCmBgYHtyfQpmaXJlc19zbWFsbCAlPiUKICBzdW1tYXJpc2UobnVtX25hID0gc3VtKGlzLm5hKGNvbnRfZGF0ZSkpKQpgYGAKKkxpdGVyYWxseSBoYWxmIHRoZSBkYXRhIGlzIG1pc3NpbmcgZm9yIGJ1cm4gdGltZSwgbWFraW5nIGl0IHZlcnkgZGlmZmljdWx0IHRvIGRvIGFueSBtZWFuaW5nZnVsIGFuYWx5c2lzKgoKCgojIyMgRmlyZXMgYnkgc2l6ZQoKCmBgYHtyfQpmaXJlc19zbWFsbCAlPiUKICBncm91cF9ieShmaXJlX3NpemVfY2xhc3MpICU+JQogIHN1bW1hcmlzZShudW1fZmlyZXMgPSBuKCkpICU+JQogIGdncGxvdCArCiAgYWVzKHggPSBmaXJlX3NpemVfY2xhc3MsIHkgPSBudW1fZmlyZXMsIGZpbGwgPSBmaXJlX3NpemVfY2xhc3MpICsKICBnZW9tX2NvbCgpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJyZWQiLCAib3JhbmdlIiwgInllbGxvdyIsICJncmVlbiIsICJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHVycGxlIiwgImJsYWNrIiksCiAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJGaXJlIFNpemUgQ2xhc3NpZmljYXRpb24iLAogICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoIkEiLCAiQiIsICJDIiwgIkQiLCAiRSIsICJGIiwgIkciKSwKICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJBOiA8IDEvNCBhY3JlIiwgIkI6IDEvNCB0byAxMCBhY3JlcyIsICJDOiAxMCB0byAxMDAgYWNyZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkQ6IDEwMCB0byAzMDAgYWNyZXMiLCAiRTogMzAwIHRvIDEwMDAgYWNyZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkY6IDEwMDAgdG8gNTAwMCBhY3JlcyIsICJHOiBNb3JlIHRoYW4gNTAwMCBhY3JlcyIpKQoKYGBgCgoKCiMgR2VvIFNwYXRpYWwgd3JhbmdsaW5nIAoKCiMjIyBUbyBtYWtlIGl0IGVhc2llciB0byB2aXN1YWxseSBkZXRlY3QgZnJlcXVlbmN5IG9mIHdpbGRmaXJlcyBiZXR3ZWVuIHN0YXRlcyBJIHdhbnQgZGlzcGxheSBpdCBpbiBhIG1hcCBmb3JtYXQuICBBcyBJJ20gdXNpbmcgZ2dwbG90MiBhbHJlYWR5IEknbSBnb2luZyB0byBhbHNvIHVzZSBpdCBmb3IgbWFwcyB3aXRoIHRoZSBgZ2VvbV9wb2x5Z29uKClgLCBgY29vcmRfbWFwKClgIGFsb25nIHdpdGggdGhlIGdndGhlbWVzIGB0aGVtZV9tYXAoKWAgZnVuY3Rpb25zLgoKCiMjIyMgSSdtIG5vdCBlbnRpcmVseSBzdXJlIHdoYXQgZ2VvLXNwYXRpYWwgaW5mb3JtYXRpb24gaXMgYmVpbmcgaGVsZCB3aXRoIGluIHRoZSBzcWxpdGUgZGF0YWJhc2UgZmlsZSwgSSd2ZSBtYWRlIGEgZmV3IGF0dGVtcHRzIHRvIHJldHJpZXZlIGl0IGJ1dCBoYXZlIGJlZW4gdW5zdWNjZXNzZnVsLiAgVGhlcmVmb3JlIEknbSBnb2luZyB0byB1dGVsaXNlIHRoZSBgZGF0YXNldHNgIHBhY2thZ2Ugd2hpY2ggaW5jbHVkZXMgdmFyaW91cyBiaXRzIG9mIGluZm9ybWF0aW9uIG9uIHRoZSBVUyBTdGF0ZXMsIGluY2x1ZGluZyBjb29yZGluYXRlcyBmb3Igc3RhdGUgYm91bmRhcmllcy4KCgpgYGB7cn0KIyBTdGF0ZSBib3VuZGFyeSBjby1vcmRpbmF0ZXMgZnJvbSAnZGF0YXNldHMnIHBhY2thZ2UKCnN0YXRlX21hcCA8LSBtYXBfZGF0YSgic3RhdGUiKQpzdGF0ZV9tYXAKYGBgCgoKIyMjIyBBbm5veWluZ2x5IGl0IGRvZXNuJ3QgaGF2ZSB0aGUgYWJicmV2aWF0aW9uIG9mIHRoZSBTdGF0ZSwgb25seSB0aGUgZnVsbCBuYW1lIHNvIEkgbmVlZCB0byBhZGQgdGhhdCBpbi4gIEx1Y2tpbHkgdGhlICdkYXRhc2V0cycgcGFja2FnZSBhbHNvIGhhcyBhIHZlY3RvciBvZiBTdGF0ZXMgbmFtZXMgYW5kIGFiYnJldmlhdGlvbnMgc28gSSBzaGFsbCBtYWtlIGEgdGliYmxlIHdpdGggdGhlbSBib3RoIGluLgoKCmBgYHtyfQpzdGF0ZS5hYmIKYGBgCgpgYGB7cn0Kc3RhdGUubmFtZQpgYGAKCmBgYHtyfQpzdGF0ZV9saXN0IDwtIHRpYmJsZShzdGF0ZSA9IHN0YXRlLmFiYiwgc3RhdGVfbmFtZSA9IHN0YXRlLm5hbWUpCnN0YXRlX2xpc3QKYGBgCgoKIyMjIyBUaGUgYHN0YXRlX21hcGAgZGF0YWZyYW1lIGlzIGluIGxvd2VyIGNhc2UgYW5kIGhhcyB0aGUgY29sdW1uIG5hbWUgJ3JlZ2lvbicuICBJIHNoYWxsIGNoYW5nZSB0aGUgYHN0YXRlX2xpc3RgIHRpYmJsZSB0byBiZSB0aGUgc2FtZSBmb3JtYXQgc28gdGhleSBjYW4gYmUgam9pbmVkIHRvZ2V0aGVyLgoKCmBgYHtyfQpzdGF0ZV9saXN0IDwtIHRpYmJsZShzdGF0ZSA9IHN0YXRlLmFiYiwgcmVnaW9uID0gdG9sb3dlcihzdGF0ZS5uYW1lKSkKYGBgCgoKIyMjIyBKb2luZyBgc3RhdGVfbGlzdGAgdG8gYGZpcmVzX3NtYWxsYCBkYXRhc2V0cwoKYGBge3J9CmZpcmVzX3N0YXRlcyA8LSBmaXJlc19zbWFsbCAlPiUKICBsZWZ0X2pvaW4oc3RhdGVfbGlzdCwgYnkgPSAic3RhdGUiKQoKZmlyZXNfc3RhdGVzCmBgYAoKCiMjIyMgQ2hlY2tpbmcgdGhlIGpvaW4gaGFzIHdvcmtlZCBhbmQgdGhlcmUgYXJlIG5vIG1pc3NpbmcgdmFsdWVzLgoKYGBge3J9CmZpcmVzX3N0YXRlcyAlPiUKICBmaWx0ZXIoaXMubmEocmVnaW9uKSkKYGBgCgoKIyMjIyBUaGVyZSBkb2VzIHNlZW0gdG8gYmUgMjIsMTQ3IE5BcyBpbiB0aGUgJ3JlZ2lvbicgY29sdW1uIHdlIGp1c3QgbWFkZS4gIFNjcm9sbGluZyB0aHJvdWdoIHRoZXJlIGFyZSAyIG1pc3NpbmcgU3RhdGVzIG9mICdQUicgYW5kICdEQycgaW4gdGhlIGBzdGF0ZXNfbGlzdGAgdGliYmxlLgoKIyMjIyBBZnRlciBzb21lIHF1aWNrIHJlc2VhcmNoIGl0IHNlZW1zIHRoYXQgdGhlcmUgYXJlIG9ubHkgNTAgU3RhdGVzIGluIHRoZSBVUy4gV2FzaGluZ3RvbiBEQyBpcyB0ZWNoaW5jYWxseSBub3QgY291bnRlZCBhcyBhIHN0YXRlIGJ1dCBhcyBhIEZlZGVyYWwgRGlzdHJpY3QsIGFzIGl0IGlzIHRoZSBzZWF0IG9mIGdvdmVybm1lbnQsIHNvIHRoYXQgd2FzIHdoeSBpdCB3YXNuJ3QgaW5jbHVkZWQgaW4gdGhlIGBTdGF0ZXNgIHRpYmJsZSBvcmlnaW5hbGx5LiAgUFIgaXMgUHVlcnRvIFJpY28gYW5kIGlzIGFsc28gbm90IGEgc3RhdGUgYnV0IHRoZSBsYXJnZXN0IFVTIHRlcnJpdG9yeSAuCgoKIyMjIyBJIHNoYWxsIGFkZCBEQyBhbmQgUFIgaW50byB0aGUgc3RhdGVfbGlzdCBhbmQgcmUtam9pbiBpdC4KCmBgYHtyfQojIEFkZGluZyAyIG5ldyBzdGF0ZXMKCnN0YXRlLmFiYiA8LSBhcHBlbmQoc3RhdGUuYWJiLCBjKCJEQyIsICJQUiIpKQpzdGF0ZS5uYW1lIDwtIGFwcGVuZChzdGF0ZS5uYW1lLCBjKCJEaXN0cmljdCBvZiBDb2x1bWJpYSIsICJQdWVydG8gUmljbyIpKQoKc3RhdGVfbGlzdCA8LSB0aWJibGUoc3RhdGUgPSBzdGF0ZS5hYmIsIHJlZ2lvbiA9IHRvbG93ZXIoc3RhdGUubmFtZSkpCmBgYAoKCmBgYHtyfQojIFJlLWpvaW5nIHRpYmJsZXMKCmZpcmVzX3N0YXRlcyA8LSBmaXJlc19zbWFsbCAlPiUKICBsZWZ0X2pvaW4oc3RhdGVfbGlzdCwgYnkgPSAic3RhdGUiKQpgYGAKCgpgYGB7cn0KIyBDaGVja2luZyB0aGUgam9pbiBoYXMgd29ya2VkIHByb3Blcmx5IGFuZCB0aGVyZSBhcmUgbm8gTkFzCgpmaXJlc19zdGF0ZXMgJT4lCiAgZmlsdGVyKGlzLm5hKHJlZ2lvbikpCmBgYAoKYGBge3J9CiMgQ29kZSBiZWxvdyBicmluZ3MgdXAgYSAidmVjdG9yIG1lbW9yeSBleGhhdXN0ZWQgKGxpbWl0IHJlYWNoZWQ/KSIgZXJyb3IKCiMgZmlyZXNfam9pbmVkIDwtIGZpcmVzX3N0YXRlcyAlPiUKIyAgcmlnaHRfam9pbihzdGF0ZV9tYXAsIGJ5ID0gInJlZ2lvbiIpCmBgYAoKCiMjIyMgVGhlIGRhdGEgc2V0IGFuZCBnZW8gaW5mb3JtYXRpb24gaXMgdG9vIGJpZyB0byBqb2luIHNvIEknbSBnb2luZyB0byBkbyBhIHN1bW1hcmlzZSBmaXJzdCB0byBnZXQgdGhlIG51bWJlciBvZiBmaXJlcyBwZXIgcmVnaW9uIGZpcnN0LgoKYGBge3J9CmZpcmVzX2pvaW5lZCA8LSBmaXJlc19zdGF0ZXMgJT4lIAogICAgc2VsZWN0KHJlZ2lvbikgJT4lCiAgICBncm91cF9ieShyZWdpb24pICU+JQogICAgc3VtbWFyaXNlKG51bV9maXJlcyA9IG4oKSkgJT4lCiAgICByaWdodF9qb2luKHN0YXRlX21hcCwgYnkgPSAicmVnaW9uIikKYGBgCgoqKlJlc3VsdCEhICBOb3cgZG9pbmcgZmlyc3QgZ2VvIHNwYXRpYWwgdmlzdWFsaXNhdGlvbioqCgoKIyMjIFRvdGFsIFdpbGRmaXJlcyBwZXIgc3RhdGUgZnJvbSAxOTkyLTIwMTUKCmBgYHtyfQpmaXJlc19qb2luZWQgJT4lIAogICAgZ2dwbG90ICsKICAgIChhZXMoeCA9IGxvbmcsIHkgPSBsYXQsIGdyb3VwID0gZ3JvdXAsIGZpbGwgPSBudW1fZmlyZXMpKSArIAogICAgZ2VvbV9wb2x5Z29uKCkgKyAKICAgIGdlb21fcGF0aChjb2xvciA9ICJ3aGl0ZSIpICsgCiAgICBzY2FsZV9maWxsX2NvbnRpbnVvdXMobG93ID0gImRhcmtibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgaGlnaCA9ICJkYXJrcmVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIk51bWJlciBvZiBmaXJlcyIpICsgCiAgICB0aGVtZV9tYXAoKSArIAogICAgY29vcmRfbWFwKCJtb2xsd2VpZGUiKSArIAogICAgZ2d0aXRsZSgiVG90YWwgVVMgV2lsZGZpcmVzIGZyb20gMTk5Mi0yMDE1IikgKyAKICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQpgYGAKCgojIDMuIEdlbyBTcGF0aWFsIFZpc3VhbGlzYXRpb25zCgojIyMgVGhlIGRhdGFzZXQgaGFzIGEgY2F1c2Ugb2YgZmlyZSBjb2x1bW4gc28gSSBzaGFsbCBub3cgY3JlYXRlIHNvbWUgY2F1c2F0aW9uIHBsb3RzLgoKCiMjIyMgR2V0dGluZyBsaXN0IG9mIGZpcmUgY2F1c2VzCgpgYGB7cn0KZmlyZXNfc3RhdGVzICU+JQogIGRpc3RpbmN0KHN0YXRfY2F1c2VfZGVzY3IpICU+JQogIGFycmFuZ2UoLWRlc2Moc3RhdF9jYXVzZV9kZXNjcikpCmBgYAoKCiMjIyBUb3RhbCBmaXJlIGJ5IGNhdXNlIGluIHRhYnVsYXIgZm9ybQoKYGBge3J9CmZpcmVzX3N0YXRlcyAlPiUKICBzZWxlY3Qoc3RhdF9jYXVzZV9kZXNjcikgJT4lCiAgZ3JvdXBfYnkoc3RhdF9jYXVzZV9kZXNjcikgJT4lCiAgc3VtbWFyaXNlKG51bV9maXJlcyA9IG4gKCkpICU+JQogIGFycmFuZ2UoZGVzYyhudW1fZmlyZXMpKQogIApgYGAKCiMjIyBOdW1iZXIgb2YgZmlyZXMgYnkgc3RhdGUgaW4gdGFidWxhciBmb3JtCgpgYGB7cn0KZmlyZXNfc3RhdGVzICU+JQogIHNlbGVjdChyZWdpb24pICU+JQogIGdyb3VwX2J5KHJlZ2lvbikgJT4lCiAgc3VtbWFyaXNlKG51bV9maXJlcyA9IG4oKSkgJT4lCiAgYXJyYW5nZShkZXNjKG51bV9maXJlcykpCmBgYAoKCiMjIyMgQXMgdGhlIGNhdXNlIG5lZWRzIHRvIGJlIGZpbHRlcmVkIGJlZm9yZSB0aGUgbWFwIGpvaW4sIEknbSBnb2luZyB0byBlaXRoZXIgZ29pbmcgdG8gaGF2ZSB0byByZXBlYXQgYSB3aG9sZSBsb2FkIG9mIHRoZSBzYW1lIGNvZGUgaW4gZXZlcnkgc2luZ2xlIHBsb3Qgb3Igd3JpdGUgYSBmdW5jdGlvbiB0aGF0IHdpbGwgZG8gaXQgZm9yIG1lIHdpdGgsIHNhdmluZyBhIGxvdCBvZiB0eXBpbmchCgpgYGB7cn0KIyBGdW5jdGlvbiBmb3IgcGxvdHRpbmcgY2F1c2Ugb2YgZmlyZQoKY2F1c2UgPC0gZnVuY3Rpb24oY2F1c2UpIHsKICBmaXJlc19zdGF0ZXMgJT4lCiAgICBmaWx0ZXIoc3RhdF9jYXVzZV9kZXNjciA9PSBjYXVzZSkgJT4lCiAgICBzZWxlY3QocmVnaW9uKSAlPiUKICAgIGdyb3VwX2J5KHJlZ2lvbikgJT4lCiAgICBzdW1tYXJpc2UobnVtX2ZpcmVzID0gbiAoKSkgJT4lCiAgICByaWdodF9qb2luKHN0YXRlX21hcCwgYnkgPSAicmVnaW9uIikgJT4lCiAgICBnZ3Bsb3QgKwogICAgKGFlcyh4ID0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCwgZmlsbCA9IG51bV9maXJlcykpICsgCiAgICBnZW9tX3BvbHlnb24oKSArIAogICAgZ2VvbV9wYXRoKGNvbG9yID0gIndoaXRlIikgKyAKICAgIHNjYWxlX2ZpbGxfY29udGludW91cyhsb3cgPSAiZGFya2JsdWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBoaWdoID0gImRhcmtyZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiTnVtYmVyIG9mIGZpcmVzIikgKyAKICAgIHRoZW1lX21hcCgpICsgCiAgICBjb29yZF9tYXAoIm1vbGx3ZWlkZSIpICsgCiAgICBnZ3RpdGxlKHBhc3RlMCgiVG90YWwgVVMgV2lsZGZpcmVzIGNhdXNlZCBieSAiLCBjYXVzZSwgIiBmcm9tIDE5OTItMjAxNSIpKSArIAogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCn0KYGBgCgoKCiMjIyBXaWxkZmlyZXMgY2F1c2VkIGJ5IEFyc29uCgpgYGB7cn0KY2F1c2UoIkFyc29uIikKYGBgCgoqKkFyc29uIGRvZXMgc2VlbSBtb3JlIHByZXZhbGVudCBpbiB0aGUgU0Ugc3RhdGVzIG9mIE1pc3Npc3NpcHBpLCBHZW9yZ2lhLCBBbGFiYW1hIGFuZCBhbHNvIHRoZSB3ZXN0ZXJuIHN0YXRlIG9mIENhbGlmb3JuaWEuKioKCgojIyMgV2lsZGZpcmVzIGNhdXNlZCBieSBDYW1wZmlyZQoKYGBge3J9CmNhdXNlKCJDYW1wZmlyZSIpCmBgYAoKKipDYW1wZmlyZXMgYXJlIHRoZSBtb3N0IHByZXZhbGVudCBpbiB0aGUgV2VzdGVybiBzdGF0ZXMgb2YgT3JlZ29uLCBDYWxpZm9ybmlhIGFuZCBBcml6b25hLioqCgoKIyMjIFdpbGRmaXJlcyBjYXVzZWQgYnkgQ2hpbGRyZW4KCmBgYHtyfQpjYXVzZSgiQ2hpbGRyZW4iKQpgYGAKCioqRmlyZXMgYnkgY2hpbGRyZW4gYXJlIHNwcmVhZCBhYm91dCB0aGUgY291bnRyeSwgYnV0IHRoZSBtb3N0IHByZXZhbGVudCBzdGF0ZXMgYXJlIENhbGlmb3JuaWEgaW4gdGhlIFdlc3QsIEFsYWJhbWEgYW5kIFNvdXRoIENhcm9saW5hIGFuZCBOZXcgSmVyc2V5IGluIHRoZSBlYXN0LioqCgoKIyMjIFdpbGRmaXJlcyBjYXVzZWQgYnkgRGVicmlzIEJ1cm5pbmcKCmBgYHtyfQpjYXVzZSgiRGVicmlzIEJ1cm5pbmciKQpgYGAKCioqRmlyZXMgYnkgYnVybmluZyBkZWJyaXMgYXJlIG1vc3RseSBpbiB0aGUgc291dGhlcm4gd2FybWVyIHN0YXRlcyBvZiBUZXhhcywgR2VvcmdpYSBhbmQgTm9ydGggQ2Fyb2xpbmEuKioKCiMjIyBXaWxkZmlyZXMgY2F1c2VkIGJ5IEVxdWltZW50IFVzZQoKYGBge3J9CmNhdXNlKCJFcXVpcG1lbnQgVXNlIikKYGBgCgoqKk1vc3Qgb2YgdGhlIGZpcmVzIGNhdXNlZCBieSBlcXVpcG1lbnQgc2VlbSB0byBiZSBpbiBDYWxpZm9ybmlhKioKCgojIyMgV2lsZGZpcmVzIGNhdXNlZCBieSBGaXJld29ya3MKCmBgYHtyfQpjYXVzZSgiRmlyZXdvcmtzIikKYGBgCgoqKk1vc3Qgb2YgdGhlIGZpcmVzIGNhdXNlZCBieSBmaXJld29ya3Mgc2VlbSB0byBiZSBpbiB0aGUgbm9ydGggb2YgdGhlIGNvdW50cnkuICBQcmltYXJpbHkgU291dGggRGFrb3RhLCBNb250YW5hIGFuZCBXYXNoaW5ndG9uIHN0YXRlLioqCgoKIyMjIFdpbGRmaXJlcyBjYXVzZWQgYnkgTGlnaHRuaW5nCgpgYGB7cn0KY2F1c2UoIkxpZ2h0bmluZyIpCmBgYAoKKipBcGFydCBmcm9tIGEgaG90c3BvdCBvZiBsaWdodG5pbmcgc3RyaWtlcyBpbiBGbG9yaWRhLCB0aGUgdmFzdCBtYWpvcml0eSBvZiBmaXJlcyBjYXVzZWQgYnkgbGlnaHRuaW5nIGFyZSBpbiB0aGUgV2VzdCBvZiB0aGUgY291bnRyeS4gIFdpdGggdGhlIDMgbW9zdCBhZmZlY3RlZCBzdGF0ZXMgYmVpbmcgQ2FsaWZvcm5pYSwgT3JlZ29uIGFuZCBBcml6b25hLioqCgojIyMgV2lsZGZpcmVzIGNhdXNlZCBieSBNaXNjZWxsaW91cwoKYGBge3J9CmNhdXNlKCJNaXNjZWxsYW5lb3VzIikKYGBgCgoqKlRoZXJlIHNlZW1zIHRvIGJlIHF1aXRlIGEgZmV3IG1pc2NlbGxhbmVvdXMgY2xhc3NpZmljYXRpb25zIGluIENhbGlmb3JuaWEsIFRleGFzIGFuZCBOZXcgWW9yay4qKgoKCiMjIyBXaWxkZmlyZXMgY2F1c2VkIGJ5IE1pc3NpbmcvVW5kZWZpbmVkCgpgYGB7cn0KY2F1c2UoIk1pc3NpbmcvVW5kZWZpbmVkIikKYGBgCgoqKlRoZSBzdGF0ZXMgd2l0aCB0aGUgbW9zdCBtaXNzaW5nIG9yIHVuZGVmaW5lZCBkYXRhIGlzIE5vcnRoIGFuZCBTb3V0aCBDYXJvbGluYSwgT2tsYWhvbWEgYW5kIENhbGlmb3JuaWEuKioKCgojIyMgV2lsZGZpcmVzIGNhdXNlZCBieSBQb3dlcmxpbmUKCmBgYHtyfQpjYXVzZSgiUG93ZXJsaW5lIikKYGBgCgoqKlRleGFzIGhhcyB0aGUgbGFyZ2VzdCBhbW91bnQgb2Ygd2lsZGZpcmVzIGNhdXNlZCBieSBwb3dlcmxpbmVzLiAgVGhpcyBpcyBsaWtlbHkgZHVlIHRvIHRoZSB3YXJtIGNsaW1hdGUgYW5kIHRoZSBsYXJnZSBwcm9wb3J0aW9uIG9mIHRoZSBzdGF0ZSB0aGF0IGlzIGRyeSBncmFzc2xhbmRzIHVzZWQgZm9yIGFncmljdWx0dXJlLioqCgoKIyMjIFdpbGRmaXJlcyBjYXVzZWQgYnkgUmFpbHJvYWQKCmBgYHtyfQpjYXVzZSgiUmFpbHJvYWQiKQpgYGAKCioqQnkgZmFyIEZsb3JpZGEgaGFzIHRoZSBtb3N0IHdpbGRmaXJlcyBjYXVzZWQgYnkgcmFpbHJvYWRzLioqCgoKIyMjIFdpbGRmaXJlcyBjYXVzZWQgYnkgU21va2luZwoKYGBge3J9CmNhdXNlKCJTbW9raW5nIikKYGBgCgoqKkZpcmVzIGNhdXNlZCBieSBzbW9raW5nIHNlZW0gdG8gYmUgc3ByZWFkIGFyb3VuZCB0aGUgY291bnRyeSwgYnV0IG1haW5seSBvbiB0aGUgZWFzdCBhbmQgd2VzdCBjb2FzdHMuKioKCgojIyMgV2lsZGZpcmVzIGNhdXNlZCBieSBTdHJ1Y3R1cmUKCmBgYHtyfQpjYXVzZSgiU3RydWN0dXJlIikKYGBgCgoqKlNvdXRoIERha290YSBoYXMgdGhlIGxhcmdlc3QgcHJvcG9ydGlvbiBvZiBmaXJlcyBjYXVzZWQgYnkgc3RydWN0dXJlcy4qKgoKCgojIyMjIFVuc3VycHJpc2luZ2x5IHRoZSBzb3V0aGVybiBzdGF0ZXMgc2VlbSB0byBoYXZlIG1vcmUgb2NjdXJlbmNlcyBvZiB3aWxkaWZyZSBpbiBnZW5lcmFsLCBubyBkb3VidCBkdWUgdG8gdGhlIHdhcm1lciBjbGltYXRlIGF0IHRoZWlyIGxhdGl0dWRlcy4gIEFsc28gdGhlIDFzdCBhbmQgM3JkIHN0YXRlcyB3aXRoIHRoZSBoaWdoZXN0IG51bWJlciBvZiBmaXJlcyBhcmUgYWxzbyB0aGUgMiBsYXJnZXN0IFN0YXRlcyBieSBzaXplLiBIb3dldmVyIHRoZSAybmQgaGlnaGVzdCBTdGF0ZSBpcyBHZW9yZ2lhLCB3aGljaCBhbHRob3VnaCBpdCBpcyBpbiB0aGUgU291dGggb2YgdGhlIGNvdW50cnkgaXMgb25seSBhbiBhdmVyYWdlIHNpemVkIFN0YXRlLiAgVGhlcmVmb3JlIHRvIGdldCBhIGJldHRlciBwaWN0dXJlIG9mIHdoYXQgaXMgZ29pbmcgb24gSSdtIGdvaW5nIHRvIGxvb2sgYXQgdGhlIHByb3BvcnRpb24gb2YgZmlyZXMgb2NjdXJpbmcgYnkgc3F1YXJlIG1pbGUgYnkgbm9ybWFsaXNpbmcgdGhlIFN0YXRlIHNpemUuCgojIyMjIFRoZSBgZGF0YXNldGAgcGFja2FnZSBhbHNvIGhhcyB0aGUgYXJlYSBpbiBzcXVhcmUgbWlsZXMgb2YgZWFjaCBzdGF0ZSBpbmNsdWRlZCBpbiB0aGUgYHN0YXRlLmFyZWFgIHZlY3Rvci4KCmBgYHtyfQpzdGF0ZS5hcmVhCmBgYAoKYGBge3J9Cmxlbmd0aChzdGF0ZS5hcmVhKQpgYGAKCiMjIyMgQW5ub3lpbmdseSBpdCBhbHNvIG9ubHkgaGFzIDUwIHN0YXRlcyBub3QgNTIgc28gSSB3aWxsIG5lZWQgdG8gYWRkIGluIERDIGFuZCBQUiBiYWNrIGluLiAgCgooQXJlYSBmaWd1cmVzIG9idGFpbmVkIGZyb20gV2lraXBlZGlhKQoKREMgPSA2OCBtaWxlc14yClBSID0gMzUxNSBtaWxlc14yCgoKYGBge3J9CiMgVG8gbWFrZSBteSBsaWZlIGVhc2llciBJJ20gZ29pbmcgdG8gcmVtb3ZlIHRoZSBzdGF0ZS5hYmIgYW5kIC5uYW1lIGZpbGVzIGFuZCBtYWtlIHRoZSB0aWJibGUgYWdhaW4sIGFkZGluZyBpbiB0aGUgbGFuZCBhcmVhIGZpZ3VyZXMgYXQgdGhlIHNhbWUgdGltZSB0byBtYWtlIHN1cmUgdGhleSBhcmUgaW4gdGhlIGNvcnJlY3Qgb3JkZXIuCgpybShzdGF0ZS5hYmIpCnJtKHN0YXRlLm5hbWUpCgpzdGF0ZS5hYmIgPC0gYXBwZW5kKHN0YXRlLmFiYiwgYygiREMiLCAiUFIiKSkKc3RhdGUubmFtZSA8LSBhcHBlbmQoc3RhdGUubmFtZSwgYygiRGlzdHJpY3Qgb2YgQ29sdW1iaWEiLCAiUHVlcnRvIFJpY28iKSkKc3RhdGUuYXJlYSA8LSBhcHBlbmQoc3RhdGUuYXJlYSwgYygiNjgiLCAiMzUxNSIpKQoKc3RhdGVfbGlzdCA8LSB0aWJibGUoc3RhdGUgPSBzdGF0ZS5hYmIsIHJlZ2lvbiA9IHRvbG93ZXIoc3RhdGUubmFtZSksIGFyZWEgPSBhcy5udW1lcmljKHN0YXRlLmFyZWEpKQpgYGAKCmBgYHtyfQojIFJlLWpvaW5pbmcgdGliYmxlcwoKZmlyZXNfc3RhdGVzIDwtIGZpcmVzX3NtYWxsICU+JQogIGxlZnRfam9pbihzdGF0ZV9saXN0LCBieSA9ICJzdGF0ZSIpCmBgYAoKCiMjIyBOb3JtYWxpc2luZyBTdGF0ZXMgYXJlYSBzaXplcwoKYGBge3J9CmZpcmVzX3N0YXRlcyAlPiUKICBzZWxlY3QocmVnaW9uLCBhcmVhKSAlPiUKICBncm91cF9ieShyZWdpb24sIGFyZWEpICU+JQogIHN1bW1hcmlzZShudW1fZmlyZXMgPSBuKCkpICU+JQogIG11dGF0ZShmaXJlc19zcW1pbGUgPSBudW1fZmlyZXMgLyBhcmVhKSAlPiUKICBhcnJhbmdlKGRlc2MoZmlyZXNfc3FtaWxlKSkKYGBgCgojIyMjIFRoaXMgdGFibGUgc2hvd3MgUHVlcnRvIFJpY28gaGFzIHRoZSBoaWdoZXN0IHByb3BvcnRpb24gb2YgZmlyZXMgY29tcGFyZWQgdG8gaXRzIHNpemUsIGZvbGxvd2VkIGJ5IE5ldyBKZXJzZXkgaW4gdGhlIE5FIG9mIHRoZSBjb3VudHJ5IGFuZCBmaW5hbGx5IGJ5IHRoZSBTdGF0ZXMgaW4gdGhlIFNFIG9mIHRoZSBjb3VudHJ5LgoKCmBgYHtyfQpmaXJlc19zdGF0ZXMgJT4lCiAgc2VsZWN0KHJlZ2lvbiwgYXJlYSkgJT4lCiAgZ3JvdXBfYnkocmVnaW9uLCBhcmVhKSAlPiUKICBzdW1tYXJpc2UobnVtX2ZpcmVzID0gbigpKSAlPiUKICBtdXRhdGUoZmlyZXNfc3FtaWxlID0gbnVtX2ZpcmVzIC8gYXJlYSkgJT4lCiAgcmlnaHRfam9pbihzdGF0ZV9tYXAsIGJ5ID0gInJlZ2lvbiIpICU+JQogIGdncGxvdCArCiAgKGFlcyh4ID0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCwgZmlsbCA9IGZpcmVzX3NxbWlsZSkpICsgCiAgZ2VvbV9wb2x5Z29uKCkgKyAKICBnZW9tX3BhdGgoY29sb3IgPSAid2hpdGUiKSArIAogIHNjYWxlX2ZpbGxfZGlzdGlsbGVyKG5hbWUgPSAiRmlyZSBwZXIgU3EgTWlsZSIsIHBhbGV0dGUgPSAiUHVCdUduIikgKwogIHRoZW1lX21hcCgpICsgCiAgY29vcmRfbWFwKCJtb2xsd2VpZGUiKSArIAogIGdndGl0bGUocGFzdGUwKCJUb3RhbCBVUyBXaWxkZmlyZXMgcGVyIFNxdWFyZSBNaWxlIGZyb20gMTk5Mi0yMDE1IikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCmBgYAoKKipQdWVydG8gUmljbyBpcyBub3Qgc2hvd24gb24gdGhpcyBtYXAsIGJ1dCB2aXN1YWxseSB3ZSBjYW4gc2VlIHRoZSBkYXRhIGZvciB0aGUgb3RoZXIgNTEgZW50cmllcywgYW5kIHRoZSBzb3V0aCBlYXN0ZXJuIHN0YXRlcyBzdGlsbCBoYXZlIHRoZSBoaWdoZXN0IHByb3BvcnRpb24gb2Ygd2lsZGZpcmVzLiAgSW50ZXJlc3RpbmdseSBOZXcgSmVyc2V5IGFsc28gc2hvd3MgaGFzIGEgaG90c3BvdCBpbiB0aGUgTkUgb2YgdGhlIGNvdW50cnkuKioKCgojIyMgRG8gY2F1c2VzIGNoYW5nZSBvdmVyIHRpbWU/CgoKIyMjIyBTcGxpdHRpbmcgY2F1c2VzIGludG8gMiBncm91cCBmb3IgbGVnaWJpbGl0eS4gCgojIyMjIFRoZSBmaXJzdCBncm91cCBpcyBmb3IgZGlyZWN0bHkgbWFuIGNyZWF0ZWQgZmlyZXMuCgpgYGB7cn0KZmlyZXNfc3RhdGVzICU+JQogIHNlbGVjdChzdGF0X2NhdXNlX2Rlc2NyLCBmaXJlX3llYXIpICU+JQogIGdyb3VwX2J5KGZpcmVfeWVhciwgc3RhdF9jYXVzZV9kZXNjcikgJT4lCiAgZmlsdGVyKHN0YXRfY2F1c2VfZGVzY3IgPT0gIkFyc29uIiB8IHN0YXRfY2F1c2VfZGVzY3IgPT0gIkNhbXBmaXJlIiB8CiAgICAgICAgICAgc3RhdF9jYXVzZV9kZXNjciA9PSAiQ2hpbGRyZW4iIHwgc3RhdF9jYXVzZV9kZXNjciA9PSAiRXF1aXBtZW50IFVzZSIgfAogICAgICAgICAgIHN0YXRfY2F1c2VfZGVzY3IgPT0gIkZpcmV3b3JrcyIgfCBzdGF0X2NhdXNlX2Rlc2NyID09ICJTbW9raW5nIikgJT4lCiAgc3VtbWFyaXNlKG51bV9maXJlcyA9IG4oKSkgJT4lCiAgZ2dwbG90ICsKICBhZXMoeCA9IGZpcmVfeWVhciwgeSA9IG51bV9maXJlcywgY29sb3VyID0gc3RhdF9jYXVzZV9kZXNjcikgKwogIGdlb21fbGluZSgpCmBgYAoKKipUaGUgMiBsYXJnZSBwZWFrcyBpbiBBcnNvbiBhcmUgb2J2aW91cyBpbiAxOTk5IGFuZCAyMDA2LiBUaGVyZSB3YXMgYSBsYXJnZSBoZWF0d2F2ZSBpbiAyMDA2LCBidXQgSSdtIG5vdCBzdXJlIHdoeSB0aGlzIHdvdWxkIHJlc3VsdCBpbiBhbiBpbmNyZWFzZSBpbiBhcnNvbi4gIFVubGVzcyB0aGlzIHdhcyBqc3V0IGR1ZSB0byB0aGUgZHJ5IGdyb3VuZCBjcmVhdGluZyBleHRyYSBmdWVsIHRvIGFpZCB0aGUgc3ByZWFkIG9mIGZpcmVzIHRoYXQgd291bGQgaGF2ZSBub3JtYWxseSBub3QgcmVzdWx0ZWQgaW4gYSBsYXJnZSBzY2FsZSBmaXJlLiAgVGhpcyBtYXkgYWxzbyBiZSB0aGUgc2FtZSByZWFzb24gdGhhdCB0aGVyZSBpcyBhbHNvIGFub3RoZXIgcGVhayBpbiAyMDA2IGZvciBFcXVpcG1lbnQgVXNlLiAgQXJzb24gaG93ZXZlciBkb2VzIGxvb2sgdG8gYmUgZGVjcmVhc2luZyBzaW5jZSAyMDA2LioqCgoKIyMjIyBBbmQgdGhpcyBvbmUgZm9yIG5hdHVyYWwgb2NjdXJpbmcgZmlyZXMuCgpgYGB7cn0KZmlyZXNfc3RhdGVzICU+JQogIHNlbGVjdChzdGF0X2NhdXNlX2Rlc2NyLCBmaXJlX3llYXIpICU+JQogIGdyb3VwX2J5KGZpcmVfeWVhciwgc3RhdF9jYXVzZV9kZXNjcikgJT4lCiAgZmlsdGVyKHN0YXRfY2F1c2VfZGVzY3IgPT0gIkRlYnJpcyBCdXJuaW5nIiB8IHN0YXRfY2F1c2VfZGVzY3IgPT0gIkxpZ2h0bmluZyIgfAogICAgICAgICAgIHN0YXRfY2F1c2VfZGVzY3IgPT0gIk1pc2NlbGxhbmVvdXMiIHwgc3RhdF9jYXVzZV9kZXNjciA9PSAKICAgICAgICAgICAiTWlzc2luZy9VbmRlZmluZWQiIHwgc3RhdF9jYXVzZV9kZXNjciA9PSAiUG93ZXJsaW5lIiB8IAogICAgICAgICAgIHN0YXRfY2F1c2VfZGVzY3IgPT0gIlJhaWxyb2FkIiB8IHN0YXRfY2F1c2VfZGVzY3IgPT0gIlN0cnVjdHVyZSIpICU+JQogIHN1bW1hcmlzZShudW1fZmlyZXMgPSBuKCkpICU+JQogIGdncGxvdCArCiAgYWVzKHggPSBmaXJlX3llYXIsIHkgPSBudW1fZmlyZXMsIGNvbG91ciA9IHN0YXRfY2F1c2VfZGVzY3IpICsKICBnZW9tX2xpbmUoKQpgYGAKCioqU2ltaWxhciBwZWFrcyBjYW4gYmUgc2VlbiBpbiBEZWJyaXMsIE1pc2NlbGxhbmVvdXMgYW5kIGxpZ2h0bmluZyBpbiB0aGUgaGVhdHdhdmUgb2YgMjAwNiB0aGF0IGxlZnQgdGhlIGdyb3VuZCB2ZXJ5IGRyeS4gIFRoZXJlIGFyZSBwZWFrcyBmcm9tIDE5OTcgdG8gMjAwMyBpbiBkZWJyaXMsIG1pc2NlbGxhbmVvdXMgYW5kIGxpZ2h0ZW5pbmcsIGJ1dCBhbHNvIGEgdHJvdWdoIGluIG1pc3NpbmcvdW5kZWZpbmVkLCBzbyB0aGlzIGlzIGxpa2VseSB0byBiZSBkdWUgdG8gbW9yZSBhY2N1cmF0ZSBjbGFzc2lmaWNhdGlvbiBvZiBmaXJlcyBhbmQgbm90IHVzaW5nIHRoZSBtaXNzaW5nL3VuZGVmaW5lZCBjYXRlZ29yeSBhcyBtdWNoLioqCgoKCiMjIyBEaWZmZXJlbmNlIGluIGNhdXNlcyBiZXR3ZWVuIHN0YXRlcwoKCmBgYHtyfQpzdGF0ZV9tYXBfc291dGhlcm4gPC0gc3RhdGVfbWFwICU+JQogIGZpbHRlcihyZWdpb24gPT0gImZsb3JpZGEiIHwgcmVnaW9uID09ICJnZW9yZ2lhIiB8IHJlZ2lvbiA9PSAiYWxhYmFtYSIgfAogICAgICAgICAgIHJlZ2lvbiA9PSAibWlzc2lzc2lwcGkiIHwgcmVnaW9uID09ICJzb3V0aCBjYXJvbGluYSIgfCAKICAgICAgICAgICByZWdpb24gPT0gIm5vcnRoIGNhcm9saW5hIiB8IHJlZ2lvbiA9PSAidGVubmVzc2VlIiB8IAogICAgICAgICAgIHJlZ2lvbiA9PSAiYXJrYW5zYXMiIHwgcmVnaW9uID09ICJsb3Vpc2lhbmEiKQpgYGAKCgpgYGB7cn0KZmlyZXNfc3RhdGVzICU+JQogIGZpbHRlcihmaXJlX3llYXIgPT0gIjE5OTIiIHwgZmlyZV95ZWFyID09ICIxOTkzIiB8IGZpcmVfeWVhciA9PSAiMTk5NCIgfAogICAgICAgICAgIGZpcmVfeWVhciA9PSAiMTk5NSIpICU+JQogIGZpbHRlcihyZWdpb24gPT0gImZsb3JpZGEiIHwgcmVnaW9uID09ICJnZW9yZ2lhIiB8IHJlZ2lvbiA9PSAiYWxhYmFtYSIgfAogICAgICAgICAgIHJlZ2lvbiA9PSAibWlzc2lzc2lwcGkiIHwgcmVnaW9uID09ICJzb3V0aCBjYXJvbGluYSIgfCAKICAgICAgICAgICByZWdpb24gPT0gIm5vcnRoIGNhcm9saW5hIiB8IHJlZ2lvbiA9PSAidGVubmVzc2VlIiB8CiAgICAgICAgICAgcmVnaW9uID09ICJhcmthbnNhcyIgfCByZWdpb24gPT0gImxvdWlzaWFuYSIpICU+JQogIHNlbGVjdChyZWdpb24sIHN0YXRfY2F1c2VfZGVzY3IpICU+JQogIGdyb3VwX2J5KHJlZ2lvbiwgc3RhdF9jYXVzZV9kZXNjcikgJT4lCiAgc3VtbWFyaXNlKG51bV9maXJlID0gbigpKSAlPiUKICB0b3BfbigxKSAlPiUKICByaWdodF9qb2luKHN0YXRlX21hcF9zb3V0aGVybiwgYnkgPSAicmVnaW9uIikgJT4lCiAgZ2dwbG90ICsKICAoYWVzKHggPSBsb25nLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwLCBmaWxsID0gc3RhdF9jYXVzZV9kZXNjcikpICsgCiAgZ2VvbV9wb2x5Z29uKCkgKyAKICBnZW9tX3BhdGgoY29sb3IgPSAid2hpdGUiKSArIAogIHRoZW1lX21hcCgpICsgCiAgc2NhbGVfZmlsbF9icmV3ZXIobmFtZSA9ICJDYXVzZSBvZiBGaXJlcyIsIHBhbGV0dGUgPSAiUHVCdUduIikgKwogIGdndGl0bGUoIlRvdGFsIFVTIFdpbGRmaXJlcyBtYWluIGNhdXNlIGZyb20gMTk5Mi0xOTk1IikgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKYGBgCgoKYGBge3J9CmZpcmVzX3N0YXRlcyAlPiUKICBmaWx0ZXIoZmlyZV95ZWFyID09ICIxOTk2IiB8IGZpcmVfeWVhciA9PSAiMTk5NyIgfCBmaXJlX3llYXIgPT0gIjE5OTgiIHwKICAgICAgICAgICBmaXJlX3llYXIgPT0gIjE5OTkiKSAlPiUKICBmaWx0ZXIocmVnaW9uID09ICJmbG9yaWRhIiB8IHJlZ2lvbiA9PSAiZ2VvcmdpYSIgfCByZWdpb24gPT0gImFsYWJhbWEiIHwKICAgICAgICAgICByZWdpb24gPT0gIm1pc3Npc3NpcHBpIiB8IHJlZ2lvbiA9PSAic291dGggY2Fyb2xpbmEiIHwgCiAgICAgICAgICAgcmVnaW9uID09ICJub3J0aCBjYXJvbGluYSIgfCByZWdpb24gPT0gInRlbm5lc3NlZSIgfAogICAgICAgICAgIHJlZ2lvbiA9PSAiYXJrYW5zYXMiIHwgcmVnaW9uID09ICJsb3Vpc2lhbmEiKSAlPiUKICBzZWxlY3QocmVnaW9uLCBzdGF0X2NhdXNlX2Rlc2NyKSAlPiUKICBncm91cF9ieShyZWdpb24sIHN0YXRfY2F1c2VfZGVzY3IpICU+JQogIHN1bW1hcmlzZShudW1fZmlyZSA9IG4oKSkgJT4lCiAgdG9wX24oMSkgJT4lCiAgcmlnaHRfam9pbihzdGF0ZV9tYXBfc291dGhlcm4sIGJ5ID0gInJlZ2lvbiIpICU+JQogIGdncGxvdCArCiAgKGFlcyh4ID0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCwgZmlsbCA9IHN0YXRfY2F1c2VfZGVzY3IpKSArIAogIGdlb21fcG9seWdvbigpICsgCiAgZ2VvbV9wYXRoKGNvbG9yID0gIndoaXRlIikgKyAKICB0aGVtZV9tYXAoKSArIAogIHNjYWxlX2ZpbGxfYnJld2VyKG5hbWUgPSAiQ2F1c2Ugb2YgRmlyZXMiLCBwYWxldHRlID0gIlB1QnVHbiIpICsKICBnZ3RpdGxlKCJUb3RhbCBVUyBXaWxkZmlyZXMgbWFpbiBjYXVzZSBmcm9tIDE5OTYtMTk5OSIpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCmBgYAoKYGBge3J9CmZpcmVzX3N0YXRlcyAlPiUKICBmaWx0ZXIoZmlyZV95ZWFyID09ICIyMDAwIiB8IGZpcmVfeWVhciA9PSAiMjAwMSIgfCBmaXJlX3llYXIgPT0gIjIwMDIiIHwKICAgICAgICAgICBmaXJlX3llYXIgPT0gIjIwMDMiKSAlPiUKICBmaWx0ZXIocmVnaW9uID09ICJmbG9yaWRhIiB8IHJlZ2lvbiA9PSAiZ2VvcmdpYSIgfCByZWdpb24gPT0gImFsYWJhbWEiIHwKICAgICAgICAgICByZWdpb24gPT0gIm1pc3Npc3NpcHBpIiB8IHJlZ2lvbiA9PSAic291dGggY2Fyb2xpbmEiIHwgCiAgICAgICAgICAgcmVnaW9uID09ICJub3J0aCBjYXJvbGluYSIgfCByZWdpb24gPT0gInRlbm5lc3NlZSIgfAogICAgICAgICAgIHJlZ2lvbiA9PSAiYXJrYW5zYXMiIHwgcmVnaW9uID09ICJsb3Vpc2lhbmEiKSAlPiUKICBzZWxlY3QocmVnaW9uLCBzdGF0X2NhdXNlX2Rlc2NyKSAlPiUKICBncm91cF9ieShyZWdpb24sIHN0YXRfY2F1c2VfZGVzY3IpICU+JQogIHN1bW1hcmlzZShudW1fZmlyZSA9IG4oKSkgJT4lCiAgdG9wX24oMSkgJT4lCiAgcmlnaHRfam9pbihzdGF0ZV9tYXBfc291dGhlcm4sIGJ5ID0gInJlZ2lvbiIpICU+JQogIGdncGxvdCArCiAgKGFlcyh4ID0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCwgZmlsbCA9IHN0YXRfY2F1c2VfZGVzY3IpKSArIAogIGdlb21fcG9seWdvbigpICsgCiAgZ2VvbV9wYXRoKGNvbG9yID0gIndoaXRlIikgKyAKICB0aGVtZV9tYXAoKSArIAogIHNjYWxlX2ZpbGxfYnJld2VyKG5hbWUgPSAiQ2F1c2Ugb2YgRmlyZXMiLCBwYWxldHRlID0gIlB1QnVHbiIpICsKICBnZ3RpdGxlKCJUb3RhbCBVUyBXaWxkZmlyZXMgbWFpbiBjYXVzZSBmcm9tIDIwMDAtMjAwMyIpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCmBgYAoKCmBgYHtyfQpmaXJlc19zdGF0ZXMgJT4lCiAgZmlsdGVyKGZpcmVfeWVhciA9PSAiMjAwNCIgfCBmaXJlX3llYXIgPT0gIjIwMDUiIHwgZmlyZV95ZWFyID09ICIyMDA2IiB8CiAgICAgICAgICAgZmlyZV95ZWFyID09ICIyMDA3IikgJT4lCiAgZmlsdGVyKHJlZ2lvbiA9PSAiZmxvcmlkYSIgfCByZWdpb24gPT0gImdlb3JnaWEiIHwgcmVnaW9uID09ICJhbGFiYW1hIiB8CiAgICAgICAgICAgcmVnaW9uID09ICJtaXNzaXNzaXBwaSIgfCByZWdpb24gPT0gInNvdXRoIGNhcm9saW5hIiB8IAogICAgICAgICAgIHJlZ2lvbiA9PSAibm9ydGggY2Fyb2xpbmEiIHwgcmVnaW9uID09ICJ0ZW5uZXNzZWUiIHwKICAgICAgICAgICByZWdpb24gPT0gImFya2Fuc2FzIiB8IHJlZ2lvbiA9PSAibG91aXNpYW5hIikgJT4lCiAgc2VsZWN0KHJlZ2lvbiwgc3RhdF9jYXVzZV9kZXNjcikgJT4lCiAgZ3JvdXBfYnkocmVnaW9uLCBzdGF0X2NhdXNlX2Rlc2NyKSAlPiUKICBzdW1tYXJpc2UobnVtX2ZpcmUgPSBuKCkpICU+JQogIHRvcF9uKDEpICU+JQogIHJpZ2h0X2pvaW4oc3RhdGVfbWFwX3NvdXRoZXJuLCBieSA9ICJyZWdpb24iKSAlPiUKICBnZ3Bsb3QgKwogIChhZXMoeCA9IGxvbmcsIHkgPSBsYXQsIGdyb3VwID0gZ3JvdXAsIGZpbGwgPSBzdGF0X2NhdXNlX2Rlc2NyKSkgKyAKICBnZW9tX3BvbHlnb24oKSArIAogIGdlb21fcGF0aChjb2xvciA9ICJ3aGl0ZSIpICsgCiAgdGhlbWVfbWFwKCkgKyAKICBzY2FsZV9maWxsX2JyZXdlcihuYW1lID0gIkNhdXNlIG9mIEZpcmVzIiwgcGFsZXR0ZSA9ICJQdUJ1R24iKSArCiAgZ2d0aXRsZSgiVG90YWwgVVMgV2lsZGZpcmVzIG1haW4gY2F1c2UgZnJvbSAyMDA0LTIwMDciKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQpgYGAKCgpgYGB7cn0KZmlyZXNfc3RhdGVzICU+JQogIGZpbHRlcihmaXJlX3llYXIgPT0gIjIwMDgiIHwgZmlyZV95ZWFyID09ICIyMDA5IiB8IGZpcmVfeWVhciA9PSAiMjAxMCIgfAogICAgICAgICAgIGZpcmVfeWVhciA9PSAiMjAxMSIpICU+JQogIGZpbHRlcihyZWdpb24gPT0gImZsb3JpZGEiIHwgcmVnaW9uID09ICJnZW9yZ2lhIiB8IHJlZ2lvbiA9PSAiYWxhYmFtYSIgfAogICAgICAgICAgIHJlZ2lvbiA9PSAibWlzc2lzc2lwcGkiIHwgcmVnaW9uID09ICJzb3V0aCBjYXJvbGluYSIgfCAKICAgICAgICAgICByZWdpb24gPT0gIm5vcnRoIGNhcm9saW5hIiB8IHJlZ2lvbiA9PSAidGVubmVzc2VlIiB8CiAgICAgICAgICAgcmVnaW9uID09ICJhcmthbnNhcyIgfCByZWdpb24gPT0gImxvdWlzaWFuYSIpICU+JQogIHNlbGVjdChyZWdpb24sIHN0YXRfY2F1c2VfZGVzY3IpICU+JQogIGdyb3VwX2J5KHJlZ2lvbiwgc3RhdF9jYXVzZV9kZXNjcikgJT4lCiAgc3VtbWFyaXNlKG51bV9maXJlID0gbigpKSAlPiUKICB0b3BfbigxKSAlPiUKICByaWdodF9qb2luKHN0YXRlX21hcF9zb3V0aGVybiwgYnkgPSAicmVnaW9uIikgJT4lCiAgZ2dwbG90ICsKICAoYWVzKHggPSBsb25nLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwLCBmaWxsID0gc3RhdF9jYXVzZV9kZXNjcikpICsgCiAgZ2VvbV9wb2x5Z29uKCkgKyAKICBnZW9tX3BhdGgoY29sb3IgPSAid2hpdGUiKSArIAogIHRoZW1lX21hcCgpICsgCiAgc2NhbGVfZmlsbF9icmV3ZXIobmFtZSA9ICJDYXVzZSBvZiBGaXJlcyIsIHBhbGV0dGUgPSAiUHVCdUduIikgKwogIGdndGl0bGUoIlRvdGFsIFVTIFdpbGRmaXJlcyBtYWluIGNhdXNlIGZyb20gMjAwOC0yMDExIikgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKYGBgCgoKCmBgYHtyfQpmaXJlc19zdGF0ZXMgJT4lCiAgZmlsdGVyKGZpcmVfeWVhciA9PSAiMjAxMiIgfCBmaXJlX3llYXIgPT0gIjIwMTMiIHwgZmlyZV95ZWFyID09ICIyMDE0IiB8CiAgICAgICAgICAgZmlyZV95ZWFyID09ICIyMDE1IikgJT4lCiAgZmlsdGVyKHJlZ2lvbiA9PSAiZmxvcmlkYSIgfCByZWdpb24gPT0gImdlb3JnaWEiIHwgcmVnaW9uID09ICJhbGFiYW1hIiB8CiAgICAgICAgICAgcmVnaW9uID09ICJtaXNzaXNzaXBwaSIgfCByZWdpb24gPT0gInNvdXRoIGNhcm9saW5hIiB8IAogICAgICAgICAgIHJlZ2lvbiA9PSAibm9ydGggY2Fyb2xpbmEiIHwgcmVnaW9uID09ICJ0ZW5uZXNzZWUiIHwKICAgICAgICAgICByZWdpb24gPT0gImFya2Fuc2FzIiB8IHJlZ2lvbiA9PSAibG91aXNpYW5hIikgJT4lCiAgc2VsZWN0KHJlZ2lvbiwgc3RhdF9jYXVzZV9kZXNjcikgJT4lCiAgZ3JvdXBfYnkocmVnaW9uLCBzdGF0X2NhdXNlX2Rlc2NyKSAlPiUKICBzdW1tYXJpc2UobnVtX2ZpcmUgPSBuKCkpICU+JQogIHRvcF9uKDEpICU+JQogIHJpZ2h0X2pvaW4oc3RhdGVfbWFwX3NvdXRoZXJuLCBieSA9ICJyZWdpb24iKSAlPiUKICBnZ3Bsb3QgKwogIChhZXMoeCA9IGxvbmcsIHkgPSBsYXQsIGdyb3VwID0gZ3JvdXAsIGZpbGwgPSBzdGF0X2NhdXNlX2Rlc2NyKSkgKyAKICBnZW9tX3BvbHlnb24oKSArIAogIGdlb21fcGF0aChjb2xvciA9ICJ3aGl0ZSIpICsgCiAgdGhlbWVfbWFwKCkgKyAKICBzY2FsZV9maWxsX2JyZXdlcihuYW1lID0gIkNhdXNlIG9mIEZpcmVzIiwgcGFsZXR0ZSA9ICJQdUJ1R24iKSArCiAgZ2d0aXRsZSgiVG90YWwgVVMgV2lsZGZpcmVzIG1haW4gY2F1c2UgZnJvbSAyMDEyLTIwMTUiKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQpgYGAKCioqTG9va2luZyBhdCB0aGVzZSB0cmVuZHMgc29tZSBpbnRlcmVzdGluZyBpbnNpZ2h0cyBjYW4gYmUgc2Vlbi4gIEZvciB0aGUgY29tYmluZWQgeWVhcnMgZGF0YSBGbG9yaWRhIHN0YW5kcyBvdXQgYXMgaGF2aW5nIHJhaWxyb2FkIGFzIGl0cyBtYWluIGNhdXNlIG9mIHdpbGRmaXJlLCBidXQgZnJvbSB0aGUgYWJvdmUgcGxvdHMgaXQgY2FuIGJlIHNlZW4gdGhhdCB0aGVzZSByYWlscm9hZCBmaXJlcyBhcmUgb25seSB0aGUgbWFpbiBjYXVzZSB1cCB0byB0aGUgNCB5ZWFybHkgcGVyaW9kIGVuZGluZyBpbiAyMDAzIGFuZCB0aGVuIHRoZSBtYWluIGNhdXNlIGNoYW5nZXMgdG8gbGlnaHRuaW5nIHVudGlsIHRoZSBlbmQgb2YgdGhlIGNvbGxlY3Rpb24gcGVyaW9kIGluIDIwMTUuICBTaW1pbGFybHkgYXJzb24gc2VlbSByZWFzb25hYmx5IHBvcHVsYXIgaW4gdGhlIHNvdXRoZXJuIHN0YXRlcyB1bnRpbCAyMDA3LCB3aGVuIGl0IG5vIGxvbmdlciBhcHBlYXIgYXMgdGhlIG1vc3QgY29tbW9uIGNhdXNlIG9mIHdpbGRmaXJlLiAgVGhpcyBkb3dud2FyZCB0cmVuZCB3YXMgYWxzbyBub3RlZCBlYXJsaWVyIGluIHRoZSBvdmVyYWxsIGNhdXNhdGlvbiBwbG90cyBmb3IgYWxsIHN0YXRlcyoqCgoKCg==